home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / source / chapter19 / isohex19_1 / isohex19_1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-20  |  38.1 KB  |  1,220 lines

  1. /*****************************************************************************
  2. IsoHex19_1.cpp
  3. Ernest S. Pazera
  4. 19SEPT2000
  5. Start a WIN32 Application Workspace, add in this file
  6. Requires the following libs:
  7. ddraw.lib, dxguid.lib
  8. Requires the following files:
  9. DDFuncs.h.cpp, GDICanvas.h/cpp, IsoMouseMap.h/cpp,
  10. IsoScroller.h/cpp, IsoTilePlotter.h/cpp, IsoTileWalker.h/cpp
  11. TileSet.h/cpp. IsoHexCore.h, IsoHexDefs.h
  12. IsoRenderer.h/cpp
  13. *****************************************************************************/
  14.  
  15. //////////////////////////////////////////////////////////////////////////////
  16. //INCLUDES
  17. //////////////////////////////////////////////////////////////////////////////
  18. #define WIN32_LEAN_AND_MEAN  
  19.  
  20. #include <windows.h>  
  21. #include "DDFuncs.h"
  22. #include "TileSet.h"
  23. #include "IsoHexCore.h"
  24. #include "IsoRenderer.h"
  25. #include <list>
  26.  
  27. //////////////////////////////////////////////////////////////////////////////
  28. //DEFINES
  29. //////////////////////////////////////////////////////////////////////////////
  30. //name for our window class
  31. #define WINDOWCLASS "ISOHEX19"
  32. //title of the application
  33. #define WINDOWTITLE "IsoHex 19-1"
  34.  
  35. const int MAPWIDTH=40;
  36. const int MAPHEIGHT=40;
  37.  
  38. //gamestates
  39. const int GS_IDLE=0;//waits for a keypress
  40. const int GS_STARTTURN=1;//starts a players turn
  41. const int GS_ENDTURN=2;//ends a players turn
  42. const int GS_NEXTUNIT=3;//finds the next unit to move
  43. const int GS_STARTMOVE=4;//starts moving the unit
  44. const int GS_DOMOVE=5;//moves the unit
  45. const int GS_ENDMOVE=6;//ends a unit move
  46. const int GS_NULLMOVE=7;//tells a unit to not move
  47. const int GS_SKIPMOVE=8;//temporarily skip the move
  48. const int GS_HOLDPOSITION=9;//fortify
  49. const int GS_CLICKSELECT=10;//when a click occurs, this gamestate is selected
  50. const int GS_CLICKCENTER=11;//click on a map location with none of the players units
  51. const int GS_CLICKSTACK=12;//click on a map location with at least two of the players units
  52. const int GS_PICKUNIT=13;//pick unit from the selection window
  53.  
  54. //////////////////////////////////////////////////////////////////////////////
  55. //TYPEDEFS/STRUCTS
  56. //////////////////////////////////////////////////////////////////////////////
  57. struct UnitInfo//unit information structure
  58. {
  59.     int iType;//type of unit
  60.     int iTeam;//team to which the unit belongs
  61.     POINT ptPosition;//map location of the unit
  62.     int iMovePoints;//number of movepoints left this turn
  63.     bool bHolding;//true if holding position
  64. };
  65.  
  66. typedef UnitInfo *PUNITINFO;//pointer type alias for unitinfo
  67.  
  68. typedef std::list<PUNITINFO> UNITLIST;//list of units
  69. typedef std::list<PUNITINFO>::iterator UNITLISTITER;//iterator for unit list
  70.  
  71. //////////////////////////////////////////////////////////////////////////////
  72. //PROTOTYPES
  73. //////////////////////////////////////////////////////////////////////////////
  74. bool Prog_Init();//game data initalizer
  75. void Prog_Loop();//main game loop
  76. void Prog_Done();//game clean up
  77.  
  78. //////////////////////////////////////////////////////////////////////////////
  79. //GLOBALS
  80. //////////////////////////////////////////////////////////////////////////////
  81. HINSTANCE hInstMain=NULL;//main application handle
  82. HWND hWndMain=NULL;//handle to our main window
  83.  
  84. //game state
  85. int iGameState=GS_IDLE;
  86. int iCurrentTeam=0;//the team whose turn it currently is
  87.  
  88. //directdraw
  89. LPDIRECTDRAW7 lpdd=NULL;
  90. LPDIRECTDRAWSURFACE7 lpddsMain=NULL;
  91. LPDIRECTDRAWSURFACE7 lpddsBack=NULL;
  92. LPDIRECTDRAWSURFACE7 lpddsFrame=NULL;
  93.  
  94. //tilesets
  95. CTileSet tsBack;//background
  96. CTileSet tsUnit;//unit
  97. CTileSet tsShield;//shields
  98. CTileSet tsPressEnter;//press enter text
  99.  
  100. //offsets for the shields
  101. POINT ptShieldOffset[2];//one for each unit
  102.  
  103. //isohexcore components
  104. CTilePlotter TilePlotter;//plotter
  105. CTileWalker TileWalker;//walker
  106. CScroller Scroller;//scroller
  107. CMouseMap MouseMap;//mousemap
  108. CRenderer Renderer;//renderer
  109.  
  110. POINT ptScroll;//keep track of how quickly we scroll
  111. POINT ptClick;//keep track of the clicked position
  112.  
  113. //map location structure
  114. struct MapLocation
  115. {
  116.     UNITLIST ulUnitList;//list of units on this map location
  117. };
  118.  
  119. MapLocation mlMap[MAPWIDTH][MAPHEIGHT];//map array
  120. UNITLIST MainUnitList;//unit list for all units
  121. UNITLIST TeamUnitList;//unit list for teams(Current Players Turn)
  122. PUNITINFO pCurrentUnit;//current unit being moved
  123. bool bFlash;//controls the flashing of the current unit
  124. ISODIRECTION idMoveUnit;//direction in which the unit will be moved
  125. bool bMovedUnit;//indicates whether or not a unit has been moved by the current player this turn
  126.  
  127. //unit selection variables(for selecting stacks of units)
  128. RECT rcSelectWindow;//the selection window
  129. POINT ptCellSize;//size of selection cell
  130. PUNITINFO SelectUnitList[20];//unit selection list (max of 20 units)
  131. POINT ptUnitOffset;//offset for placing units in the selection window
  132. DWORD dwSelectWindowColor;//color for the selection window
  133.  
  134.  
  135. //rendering functionprototype
  136. void RenderFunc(LPDIRECTDRAWSURFACE7 lpddsDst,RECT* rcClip,int xDst,int yDst,int xMap,int yMap);
  137.  
  138. //////////////////////////////////////////////////////////////////////////////
  139. //WINDOWPROC
  140. //////////////////////////////////////////////////////////////////////////////
  141. LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  142. {
  143.     //which message did we get?
  144.     switch(uMsg)
  145.     {
  146.     case WM_LBUTTONDOWN://beginning of click-select
  147.         {
  148.             //process differently, depending on gamestate
  149.             switch(iGameState)
  150.             {
  151.             case GS_IDLE:
  152.                 {
  153.                     //grab the mouse position
  154.                     POINT ptCursor;
  155.                     ptCursor.x=LOWORD(lParam);
  156.                     ptCursor.y=HIWORD(lParam);
  157.                     //use the mousemap to get click position
  158.                     ptClick=MouseMap.MapMouse(ptCursor);
  159.                 }break;
  160.             }
  161.             return(0);//handled
  162.         }break;
  163.     case WM_LBUTTONUP://end of click-select
  164.         {
  165.             //process differently, depending on gamestate
  166.             switch(iGameState)
  167.             {
  168.             case GS_IDLE:
  169.                 {
  170.                     //grab the mouse position
  171.                     POINT ptCursor;
  172.                     ptCursor.x=LOWORD(lParam);
  173.                     ptCursor.y=HIWORD(lParam);
  174.                     //use the mousemap to get click position
  175.                     POINT ptMap=MouseMap.MapMouse(ptCursor);
  176.                     //check map position against ptClick
  177.                     if(ptMap.x==ptClick.x && ptMap.y==ptClick.y)
  178.                     {
  179.                         //set gamestate to GS_CLICKSELECT
  180.                         iGameState=GS_CLICKSELECT;
  181.                     }
  182.                 }break;
  183.             case GS_PICKUNIT:
  184.                 {
  185.                     //grab the mouse position
  186.                     POINT ptMouse;
  187.                     ptMouse.x=LOWORD(lParam);
  188.                     ptMouse.y=HIWORD(lParam);
  189.                     //check to see if the click was within the select window
  190.                     if(PtInRect(&rcSelectWindow,ptMouse))
  191.                     {
  192.                         //within the select window
  193.                         //determine which cell was clicked
  194.                         ptMouse.x-=rcSelectWindow.left;//subtract top left of the window
  195.                         ptMouse.y-=rcSelectWindow.top;
  196.                         ptMouse.x/=ptCellSize.x;//divide by cellsize
  197.                         ptMouse.y/=ptCellSize.y;
  198.                         int cellnum=ptMouse.x+5*ptMouse.y;//calc cell number
  199.                         //check for a NULL
  200.                         if(SelectUnitList[cellnum]==NULL)
  201.                         {
  202.                             //empty cell
  203.                             //do nothing
  204.                             return(0);
  205.                         }
  206.                         else
  207.                         {
  208.                             //non-empty cell
  209.                             //check if the unit has any movement points left
  210.                             if(SelectUnitList[cellnum]->iMovePoints==0)
  211.                             {
  212.                                 //no movement points
  213.                                 //do nothing
  214.                                 return(0);
  215.                             }
  216.                             else
  217.                             {
  218.                                 //check for holding position
  219.                                 if(SelectUnitList[cellnum]->bHolding)
  220.                                 {
  221.                                     //set holding to false
  222.                                     SelectUnitList[cellnum]->bHolding=false;
  223.                                 }
  224.                                 //remove this unit from the team list
  225.                                 TeamUnitList.remove(SelectUnitList[cellnum]);
  226.                                 //re-add this unit to the team list at the beginning
  227.                                 TeamUnitList.push_front(SelectUnitList[cellnum]);
  228.                                 //select next unit
  229.                                 iGameState=GS_NEXTUNIT;
  230.                                 //add entire screen to update rect
  231.                                 Renderer.AddRect(Scroller.GetScreenSpace());
  232.                             }
  233.                         }
  234.                     }
  235.                     else
  236.                     {
  237.                         //outside of select window
  238.                         iGameState=GS_NEXTUNIT;
  239.                     }
  240.                 }break;
  241.             }
  242.             return(0);//handled
  243.         }break;
  244.     case WM_KEYDOWN:
  245.         {
  246.             switch(wParam)
  247.             {
  248.             case VK_ESCAPE:
  249.                 {
  250.                     DestroyWindow(hWndMain);
  251.                     return(0);
  252.                 }break;
  253.             case VK_RETURN://at end of turn, if no unit has been moved
  254.                 {
  255.                     if(iGameState==GS_IDLE && pCurrentUnit==NULL) iGameState=GS_ENDTURN;
  256.                     return(0);
  257.                 }break;
  258.             case VK_SPACE://do not move unit
  259.                 {
  260.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL) iGameState=GS_NULLMOVE;//only respond when gamestate is GS_IDLE;
  261.                     return(0);
  262.                 }break;
  263.             case 'W'://wait to move this unit later
  264.                 {
  265.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL) iGameState=GS_SKIPMOVE;//skip this unit for now
  266.                 }break;
  267.             case 'H'://tell unit to hold position
  268.                 {
  269.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL) iGameState=GS_HOLDPOSITION;//tell the unit to hold position
  270.                 }break;
  271.             case 'C'://center on the current unit
  272.                 {
  273.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)
  274.                     {
  275.                         //plot the current unit's world position
  276.                         POINT ptPlot=TilePlotter.PlotTile(pCurrentUnit->ptPosition);
  277.                         //adjust by half width and height of the screen
  278.                         ptPlot.x-=(Scroller.GetScreenSpaceWidth()/2);
  279.                         ptPlot.y-=(Scroller.GetScreenSpaceHeight()/2);
  280.                         //set the anchor
  281.                         Scroller.SetAnchor(&ptPlot);
  282.                         //add update rect to renderer
  283.                         Renderer.AddRect(Scroller.GetScreenSpace());
  284.                     }
  285.                 }break;
  286.             case VK_NUMPAD8:
  287.             case VK_UP:
  288.                 {
  289.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  290.                     {
  291.                         idMoveUnit=ISO_NORTH;//move to the north
  292.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  293.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  294.                         {
  295.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  296.                             {
  297.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  298.                             }
  299.                             else
  300.                             {
  301.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  302.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  303.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  304.                                 {
  305.                                     iGameState=GS_STARTMOVE;
  306.                                 }
  307.                             }
  308.                         }
  309.                     }
  310.                 }break;
  311.             case VK_NUMPAD9:
  312.             case VK_PRIOR:
  313.                 {
  314.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  315.                     {
  316.                         idMoveUnit=ISO_NORTHEAST;//move to the north
  317.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  318.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  319.                         {
  320.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  321.                             {
  322.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  323.                             }
  324.                             else
  325.                             {
  326.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  327.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  328.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  329.                                 {
  330.                                     iGameState=GS_STARTMOVE;
  331.                                 }
  332.                             }
  333.                         }
  334.                     }
  335.                 }break;
  336.             case VK_NUMPAD6:
  337.             case VK_RIGHT:
  338.                 {
  339.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  340.                     {
  341.                         idMoveUnit=ISO_EAST;//move to the north
  342.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  343.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  344.                         {
  345.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  346.                             {
  347.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  348.                             }
  349.                             else
  350.                             {
  351.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  352.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  353.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  354.                                 {
  355.                                     iGameState=GS_STARTMOVE;
  356.                                 }
  357.                             }
  358.                         }
  359.                     }
  360.                 }break;
  361.             case VK_NUMPAD3:
  362.             case VK_NEXT:
  363.                 {
  364.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  365.                     {
  366.                         idMoveUnit=ISO_SOUTHEAST;//move to the north
  367.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  368.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  369.                         {
  370.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  371.                             {
  372.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  373.                             }
  374.                             else
  375.                             {
  376.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  377.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  378.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  379.                                 {
  380.                                     iGameState=GS_STARTMOVE;
  381.                                 }
  382.                             }
  383.                         }
  384.                     }
  385.                 }break;
  386.             case VK_NUMPAD2:
  387.             case VK_DOWN:
  388.                 {
  389.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  390.                     {
  391.                         idMoveUnit=ISO_SOUTH;//move to the north
  392.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  393.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  394.                         {
  395.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  396.                             {
  397.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  398.                             }
  399.                             else
  400.                             {
  401.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  402.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  403.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  404.                                 {
  405.                                     iGameState=GS_STARTMOVE;
  406.                                 }
  407.                             }
  408.                         }
  409.                     }
  410.                 }break;
  411.             case VK_NUMPAD1:
  412.             case VK_END:
  413.                 {
  414.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  415.                     {
  416.                         idMoveUnit=ISO_SOUTHWEST;//move to the north
  417.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  418.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  419.                         {
  420.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  421.                             {
  422.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  423.                             }
  424.                             else
  425.                             {
  426.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  427.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  428.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  429.                                 {
  430.                                     iGameState=GS_STARTMOVE;
  431.                                 }
  432.                             }
  433.                         }
  434.                     }
  435.                 }break;
  436.             case VK_NUMPAD4:
  437.             case VK_LEFT:
  438.                 {
  439.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  440.                     {
  441.                         idMoveUnit=ISO_WEST;//move to the north
  442.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  443.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  444.                         {
  445.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  446.                             {
  447.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  448.                             }
  449.                             else
  450.                             {
  451.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  452.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  453.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  454.                                 {
  455.                                     iGameState=GS_STARTMOVE;
  456.                                 }
  457.                             }
  458.                         }
  459.                     }
  460.                 }break;
  461.             case VK_NUMPAD7:
  462.             case VK_HOME:
  463.                 {
  464.                     if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
  465.                     {
  466.                         idMoveUnit=ISO_NORTHWEST;//move to the north
  467.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  468.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  469.                         {
  470.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  471.                             {
  472.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  473.                             }
  474.                             else
  475.                             {
  476.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  477.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  478.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  479.                                 {
  480.                                     iGameState=GS_STARTMOVE;
  481.                                 }
  482.                             }
  483.                         }
  484.                     }
  485.                 }break;
  486.             }
  487.         }break;
  488.     case WM_DESTROY://the window is being destroyed
  489.         {
  490.  
  491.             //tell the application we are quitting
  492.             PostQuitMessage(0);
  493.  
  494.             //handled message, so return 0
  495.             return(0);
  496.  
  497.         }break;
  498.     case WM_PAINT://the window needs repainting
  499.         {
  500.             //a variable needed for painting information
  501.             PAINTSTRUCT ps;
  502.             
  503.             //start painting
  504.             HDC hdc=BeginPaint(hwnd,&ps);
  505.  
  506.             /////////////////////////////
  507.             //painting code would go here
  508.             /////////////////////////////
  509.  
  510.             //end painting
  511.             EndPaint(hwnd,&ps);
  512.                         
  513.             //handled message, so return 0
  514.             return(0);
  515.         }break;
  516.     }
  517.  
  518.     //pass along any other message to default message handler
  519.     return(DefWindowProc(hwnd,uMsg,wParam,lParam));
  520. }
  521.  
  522.  
  523. //////////////////////////////////////////////////////////////////////////////
  524. //WINMAIN
  525. //////////////////////////////////////////////////////////////////////////////
  526. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
  527. {
  528.     //assign instance to global variable
  529.     hInstMain=hInstance;
  530.  
  531.     //create window class
  532.     WNDCLASSEX wcx;
  533.  
  534.     //set the size of the structure
  535.     wcx.cbSize=sizeof(WNDCLASSEX);
  536.  
  537.     //class style
  538.     wcx.style=CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  539.  
  540.     //window procedure
  541.     wcx.lpfnWndProc=TheWindowProc;
  542.  
  543.     //class extra
  544.     wcx.cbClsExtra=0;
  545.  
  546.     //window extra
  547.     wcx.cbWndExtra=0;
  548.  
  549.     //application handle
  550.     wcx.hInstance=hInstMain;
  551.  
  552.     //icon
  553.     wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  554.  
  555.     //cursor
  556.     wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
  557.  
  558.     //background color
  559.     wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
  560.  
  561.     //menu
  562.     wcx.lpszMenuName=NULL;
  563.  
  564.     //class name
  565.     wcx.lpszClassName=WINDOWCLASS;
  566.  
  567.     //small icon
  568.     wcx.hIconSm=NULL;
  569.  
  570.     //register the window class, return 0 if not successful
  571.     if(!RegisterClassEx(&wcx)) return(0);
  572.  
  573.     //create main window
  574.     hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_POPUP | WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);
  575.  
  576.     //error check
  577.     if(!hWndMain) return(0);
  578.  
  579.     //if program initialization failed, then return with 0
  580.     if(!Prog_Init()) return(0);
  581.  
  582.     //message structure
  583.     MSG msg;
  584.  
  585.     //message pump
  586.     for(;;)    
  587.     {
  588.         //look for a message
  589.         if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  590.         {
  591.             //there is a message
  592.  
  593.             //check that we arent quitting
  594.             if(msg.message==WM_QUIT) break;
  595.             
  596.             //translate message
  597.             TranslateMessage(&msg);
  598.  
  599.             //dispatch message
  600.             DispatchMessage(&msg);
  601.         }
  602.  
  603.         //run main game loop
  604.         Prog_Loop();
  605.     }
  606.     
  607.     //clean up program data
  608.     Prog_Done();
  609.  
  610.     //return the wparam from the WM_QUIT message
  611.     return(msg.wParam);
  612. }
  613.  
  614. //////////////////////////////////////////////////////////////////////////////
  615. //INITIALIZATION
  616. //////////////////////////////////////////////////////////////////////////////
  617. bool Prog_Init()
  618. {
  619.     //create IDirectDraw object
  620.     lpdd=LPDD_Create(hWndMain,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
  621.  
  622.     //set display mode
  623.     lpdd->SetDisplayMode(640,480,16,0,0);
  624.  
  625.     //create primary surface
  626.     lpddsMain=LPDDS_CreatePrimary(lpdd,1);
  627.  
  628.     //get back buffer
  629.     lpddsBack=LPDDS_GetSecondary(lpddsMain);
  630.  
  631.     //create the frame buffer
  632.     lpddsFrame=LPDDS_CreateOffscreen(lpdd,640,480);
  633.  
  634.     //load in the mousemap
  635.     MouseMap.Load("MouseMap.bmp");
  636.  
  637.     //set up the tile plotter
  638.     TilePlotter.SetMapType(ISOMAP_DIAMOND);//diamond mode
  639.     TilePlotter.SetTileSize(MouseMap.GetWidth(),MouseMap.GetHeight());//grab width and height from mousemap
  640.  
  641.     //set up tile walker to diamond mode
  642.     TileWalker.SetMapType(ISOMAP_DIAMOND);
  643.  
  644.     //set up screeen space
  645.     RECT rcTemp;
  646.     SetRect(&rcTemp,0,0,640,480);
  647.     Scroller.SetScreenSpace(&rcTemp);
  648.  
  649.     //load in tiles and other images
  650.     tsBack.Load(lpdd,"backgroundts.bmp");
  651.     tsUnit.Load(lpdd,"units.bmp");
  652.     tsShield.Load(lpdd,"shields.bmp");
  653.     tsPressEnter.Load(lpdd,"PressEnter.bmp");
  654.  
  655.     //calculate the shield offsets
  656.     ptShieldOffset[0].x=tsUnit.GetTileList()[0].rcSrc.right-tsUnit.GetTileList()[0].ptAnchor.x;
  657.     ptShieldOffset[0].y=tsUnit.GetTileList()[0].rcSrc.top-tsUnit.GetTileList()[0].ptAnchor.y;
  658.     ptShieldOffset[1].x=tsUnit.GetTileList()[1].rcSrc.right-tsUnit.GetTileList()[1].ptAnchor.x;
  659.     ptShieldOffset[1].y=tsUnit.GetTileList()[1].rcSrc.top-tsUnit.GetTileList()[1].ptAnchor.y;
  660.  
  661.     //grab tile extent from tileset
  662.     CopyRect(&rcTemp,&tsBack.GetTileList()[0].rcDstExt);
  663.  
  664.     //calculate the worldspace
  665.     Scroller.CalcWorldSpace(&TilePlotter,&rcTemp,MAPWIDTH,MAPHEIGHT);
  666.  
  667.     //calculate the mousemap reference point
  668.     MouseMap.CalcReferencePoint(&TilePlotter,&rcTemp);
  669.  
  670.     //calculate anchor space
  671.     Scroller.CalcAnchorSpace();
  672.  
  673.     //set wrap modes for scroller
  674.     Scroller.SetHWrapMode(WRAPMODE_CLIP);
  675.     Scroller.SetVWrapMode(WRAPMODE_CLIP);
  676.  
  677.     //set scroller anchor to (0,0)
  678.     Scroller.GetAnchor()->x=0;
  679.     Scroller.GetAnchor()->y=0;
  680.  
  681.     //attach scrolelr and tilewalker to mousemap
  682.     MouseMap.SetScroller(&Scroller);
  683.     MouseMap.SetTileWalker(&TileWalker);
  684.  
  685.     //set up the map to a random tilefield
  686.     int x;
  687.     int y;
  688.     for(x=0;x<MAPWIDTH;x++)
  689.     {
  690.         for(y=0;y<MAPHEIGHT;y++)
  691.         {
  692.             mlMap[x][y].ulUnitList.clear();//clear out the list for this map location
  693.         }
  694.     }
  695.  
  696.     //place the units
  697.     int team;
  698.     int count;
  699.     PUNITINFO pUnitInfo;
  700.     POINT ptTest;
  701.     for(team=0;team<2;team++)//place units for both teams
  702.     {
  703.         for(count=0;count<20;count++)//place 20 units for each team
  704.         {
  705.             //check for a valid placement
  706.             bool found=false;
  707.             while(!found)
  708.             {
  709.                 //random placement
  710.                 ptTest.x=rand()%MAPWIDTH;
  711.                 ptTest.y=rand()%MAPHEIGHT;
  712.                 //check for a unit at that position
  713.                 if(mlMap[ptTest.x][ptTest.y].ulUnitList.empty())
  714.                 {
  715.                     //unit list at location is empty... you can place the unit
  716.                     found=true;
  717.                 }
  718.                 else
  719.                 {
  720.                     //unit list is not empty, so must be occupied by the same team to be a valid location
  721.                     UNITLISTITER iter=mlMap[ptTest.x][ptTest.y].ulUnitList.begin();//get iterator to beginning of list
  722.                     pUnitInfo=*iter;//grab the items stored
  723.                     //check for the same team
  724.                     if(pUnitInfo->iTeam==team)
  725.                     {
  726.                         //same team, valid location
  727.                         found=true;
  728.                     }
  729.  
  730.                 }
  731.             }
  732.             //create the unit
  733.             pUnitInfo=new UnitInfo;
  734.             pUnitInfo->iTeam=team;//team
  735.             pUnitInfo->iType=rand()%2;//type
  736.             pUnitInfo->bHolding=false;//not holding position
  737.             pUnitInfo->ptPosition=ptTest;//location
  738.             //place unit in the main list
  739.             MainUnitList.push_back(pUnitInfo);
  740.             //place unit on the map
  741.             mlMap[pUnitInfo->ptPosition.x][pUnitInfo->ptPosition.y].ulUnitList.push_back(pUnitInfo);
  742.         }
  743.     }
  744.  
  745.     //calculate the extent rect
  746.     RECT rcExtent;
  747.     CopyRect(&rcExtent,&tsBack.GetTileList()[0].rcDstExt);//set to background extent
  748.     UnionRect(&rcExtent,&rcExtent,&tsUnit.GetTileList()[0].rcDstExt);//union with unit extent
  749.     rcExtent.right+=tsShield.GetTileList()[0].rcDstExt.right;//adjust the extent for the width of the shield
  750.  
  751.     //set up the renderer
  752.     Renderer.SetBackBuffer(lpddsBack);
  753.     Renderer.SetExtentRect(&rcExtent);
  754.     Renderer.SetFrameBuffer(lpddsFrame);
  755.     Renderer.SetMapSize(MAPWIDTH,MAPHEIGHT);
  756.     Renderer.SetMouseMap(&MouseMap);
  757.     Renderer.SetPlotter(&TilePlotter);
  758.     Renderer.SetRenderFunction(RenderFunc);
  759.     Renderer.SetScroller(&Scroller);
  760.     Renderer.SetUpdateRectCount(100);
  761.     Renderer.SetWalker(&TileWalker);
  762.  
  763.     //set the initial gamestate
  764.     iGameState=GS_STARTTURN;
  765.     iCurrentTeam=0;//current team
  766.     TeamUnitList.clear();//clear out the team's unit list
  767.  
  768.     //set up the selection window variables
  769.     DDPIXELFORMAT ddpf;
  770.     DDPF_Clear(&ddpf);
  771.     lpddsMain->GetPixelFormat(&ddpf);//grab pixel format
  772.     ddpf.dwRBitMask=(ddpf.dwRBitMask*3/4)&(ddpf.dwRBitMask);//calculate 3/4 red
  773.     ddpf.dwGBitMask=(ddpf.dwGBitMask*3/4)&(ddpf.dwGBitMask);//calc 3/4 green
  774.     ddpf.dwBBitMask=(ddpf.dwBBitMask*3/4)&(ddpf.dwBBitMask);//calc 3/4 blue
  775.     dwSelectWindowColor=ddpf.dwBBitMask | ddpf.dwRBitMask | ddpf.dwGBitMask;//make select window color
  776.  
  777.     //calculate the cell size
  778.     RECT rcCell;
  779.     CopyRect(&rcCell,&tsUnit.GetTileList()[0].rcDstExt);
  780.     UnionRect(&rcCell,&rcCell,&tsUnit.GetTileList()[1].rcDstExt);
  781.     rcCell.right+=(tsShield.GetTileList()[0].rcDstExt.right-tsShield.GetTileList()[0].rcDstExt.left);
  782.     //cell size
  783.     ptCellSize.x=rcCell.right-rcCell.left;
  784.     ptCellSize.y=rcCell.bottom-rcCell.top;
  785.     //unit offset
  786.     ptUnitOffset.x=-rcCell.left;
  787.     ptUnitOffset.y=-rcCell.top;
  788.     //calculate select window rect
  789.     SetRect(&rcSelectWindow,0,0,ptCellSize.x*5,ptCellSize.y*4);
  790.     //center the select window
  791.     OffsetRect(&rcSelectWindow,320-rcSelectWindow.right/2,240-rcSelectWindow.bottom/2);
  792.     
  793.     //update the entire screenspace
  794.     Renderer.AddRect(Scroller.GetScreenSpace());
  795.  
  796.     return(true);//return success
  797. }
  798.  
  799. //////////////////////////////////////////////////////////////////////////////
  800. //CLEANUP
  801. //////////////////////////////////////////////////////////////////////////////
  802. void Prog_Done()
  803. {
  804.     //release frame buffer
  805.     LPDDS_Release(&lpddsFrame);
  806.  
  807.     //release main/back surfaces
  808.     LPDDS_Release(&lpddsMain);
  809.  
  810.     //release directdraw
  811.     LPDD_Release(&lpdd);
  812. }
  813.  
  814. //////////////////////////////////////////////////////////////////////////////
  815. //MAIN GAME LOOP
  816. //////////////////////////////////////////////////////////////////////////////
  817. void Prog_Loop()
  818. {
  819.     switch(iGameState)
  820.     {
  821.     case GS_STARTTURN://start the current team's turn
  822.         {
  823.             PUNITINFO pUnitInfo;//variable to check for the team's units
  824.             UNITLISTITER iter;//iterator for the main unit list
  825.             for(iter=MainUnitList.begin();iter!=MainUnitList.end();iter++)//iterate through the main unit list
  826.             {
  827.                 pUnitInfo=*iter;//grab the unit from the list
  828.                 if(pUnitInfo->iTeam==iCurrentTeam)//does this unit belong to the current team?
  829.                 {
  830.                     //give the unit a movement point
  831.                     pUnitInfo->iMovePoints=1+pUnitInfo->iType;
  832.                     //add this unit to the team list
  833.                     TeamUnitList.push_back(pUnitInfo);
  834.                 }
  835.             }
  836.             //set moved unit flag to false
  837.             bMovedUnit=false;
  838.             //set the next gamestate
  839.             iGameState=GS_NEXTUNIT;
  840.         }break;
  841.     case GS_NEXTUNIT://select the next unit as the current unit
  842.         {
  843.             //set current unit to NULL
  844.             pCurrentUnit=NULL;
  845.             if(TeamUnitList.empty())//if the team unit list is empty
  846.             {
  847.                 //if a unit has been moved, send to end of turn
  848.                 if(bMovedUnit)
  849.                 {
  850.                     iGameState=GS_ENDTURN;//end the turn
  851.                 }
  852.                 else
  853.                 {
  854.                     //send to GS_IDLE
  855.                     iGameState=GS_IDLE;//send to idle state
  856.                 }
  857.             }
  858.             else
  859.             {
  860.                 //turn is not over
  861.                 UNITLISTITER iter=TeamUnitList.begin();//get the first unit in the team list
  862.                 pCurrentUnit=*iter;//grab the unit from the list
  863.                 TeamUnitList.pop_front();//remove the unit from the list
  864.  
  865.                 //check to see if this unit is holding position
  866.                 if(pCurrentUnit->bHolding) return;//go to next unit
  867.  
  868.                 mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.remove(pCurrentUnit);//remove the unit from the map location
  869.                 mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.push_front(pCurrentUnit);//place unit at the top of the map locations unit list
  870.  
  871.                 POINT ptPlot=TilePlotter.PlotTile(pCurrentUnit->ptPosition);//plot the unit's location
  872.                 POINT ptScreen=Scroller.WorldToScreen(ptPlot);//translate into screen coordinates
  873.  
  874.                 if(!PtInRect(Scroller.GetScreenSpace(),ptScreen))//check to see if point is within screenspace
  875.                 {
  876.                     //not on screen
  877.                     ptPlot.x-=(Scroller.GetScreenSpaceWidth()/2);
  878.                     ptPlot.y-=(Scroller.GetScreenSpaceHeight()/2);
  879.                     //set the anchor
  880.                     Scroller.SetAnchor(&ptPlot);
  881.                     Renderer.AddRect(Scroller.GetScreenSpace());
  882.                 }
  883.                 iGameState=GS_IDLE;//set to idling gamestate
  884.             }
  885.         }break;
  886.     case GS_ENDTURN://end of a player's turn
  887.         {
  888.             //clear out team unit list(just to be sure)
  889.             TeamUnitList.clear();
  890.  
  891.             //change team
  892.             iCurrentTeam=1-iCurrentTeam;
  893.  
  894.             iGameState=GS_STARTTURN;//set gamestate to start next turn
  895.         }break;
  896.     case GS_NULLMOVE://do not move the current unit
  897.         {
  898.             //set the moved flag to true
  899.             bMovedUnit=true;
  900.             //set movement points to 0
  901.             pCurrentUnit->iMovePoints=0;
  902.             //don't really do anything, just go to the next unit
  903.             pCurrentUnit=NULL;
  904.             iGameState=GS_NEXTUNIT;
  905.         }break;
  906.     case GS_SKIPMOVE://skip this unit for now
  907.         {
  908.             //put unit at end of team unit list
  909.             TeamUnitList.push_back(pCurrentUnit);
  910.             pCurrentUnit=NULL;//set current unit to NULL
  911.             iGameState=GS_NEXTUNIT;//select the next unit
  912.         }break;
  913.     case GS_HOLDPOSITION://tell unit to hold position
  914.         {
  915.             //set holding flag
  916.             pCurrentUnit->bHolding=true;
  917.             //show the holding unit
  918.             Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  919.             pCurrentUnit=NULL;
  920.             bFlash=true;
  921.             //set next gamestate
  922.             iGameState=GS_NEXTUNIT;
  923.             DWORD dwTimeStart=GetTickCount();//get the frame start time
  924.             //scroll the frame (0,0)
  925.             Renderer.ScrollFrame(0,0);
  926.             //update the frame
  927.             Renderer.UpdateFrame();
  928.             //flip to show the back buffer
  929.             lpddsMain->Flip(0,DDFLIP_WAIT);
  930.             //wait until 500 ms have passed
  931.             while(GetTickCount()-dwTimeStart<500);
  932.         }break;
  933.     case GS_STARTMOVE:
  934.         {
  935.             //set the moved flag to true
  936.             bMovedUnit=true;
  937.             //remove the unit from the map location
  938.             mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.remove(pCurrentUnit);
  939.             Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  940.             //set next gamestate
  941.             iGameState=GS_DOMOVE;
  942.         }break;
  943.     case GS_DOMOVE:
  944.         {
  945.             //move the unit
  946.             pCurrentUnit->ptPosition=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);
  947.             //set next gamestate
  948.             iGameState=GS_ENDMOVE;
  949.         }break;
  950.     case GS_ENDMOVE:
  951.         {
  952.             //place the unit on its new map location
  953.             mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.push_front(pCurrentUnit);
  954.             Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  955.             //subtract a movement point
  956.             pCurrentUnit->iMovePoints--;
  957.             //check to see if this unit is finished moving
  958.             if(pCurrentUnit->iMovePoints==0)
  959.             {
  960.                 //done moving
  961.                 pCurrentUnit=NULL;
  962.                 //set next gamestate
  963.                 iGameState=GS_NEXTUNIT;
  964.             }
  965.             else
  966.             {
  967.                 //not done moving
  968.                 iGameState=GS_IDLE;
  969.             }
  970.             bFlash=true;
  971.             DWORD dwTimeStart=GetTickCount();//get the frame start time
  972.             //scroll the frame (0,0)
  973.             Renderer.ScrollFrame(0,0);
  974.             //update the frame
  975.             Renderer.UpdateFrame();
  976.             //flip to show the back buffer
  977.             lpddsMain->Flip(0,DDFLIP_WAIT);
  978.             //wait until 500 ms have passed
  979.             while(GetTickCount()-dwTimeStart<500);
  980.         }break;
  981.     case GS_IDLE://the game is idling, update the frame, but thats about it.
  982.         {
  983.             DWORD dwTimeStart=GetTickCount();//get the frame start time
  984.             //scroll the frame (0,0)
  985.             Renderer.ScrollFrame(0,0);
  986.  
  987.             //toggle unit flash
  988.             bFlash=!bFlash;
  989.  
  990.             //if the current unit is not null
  991.             if(pCurrentUnit!=NULL)
  992.             {
  993.                 //add the tile in which the current unit lives
  994.                 Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  995.             }
  996.  
  997.             //update the frame
  998.             Renderer.UpdateFrame();
  999.  
  1000.             //if the current unit IS null
  1001.             if(pCurrentUnit==NULL)
  1002.             {
  1003.                 //show the end of turn marker if bflash is true
  1004.                 if(bFlash) tsPressEnter.PutTile(lpddsBack,0,0,iCurrentTeam);
  1005.             }
  1006.  
  1007.             //flip to show the back buffer
  1008.             lpddsMain->Flip(0,DDFLIP_WAIT);
  1009.             //wait until 200 ms have passed
  1010.             while(GetTickCount()-dwTimeStart<200);
  1011.         }break;
  1012.     case GS_CLICKSELECT:
  1013.         {
  1014.             //check map location for emptiness
  1015.             if(mlMap[ptClick.x][ptClick.y].ulUnitList.empty())
  1016.             {
  1017.                 //map location is empty
  1018.                 iGameState=GS_CLICKCENTER;//we want to center on this map location
  1019.             }
  1020.             else
  1021.             {
  1022.                 //map location is not empty
  1023.                 //look at top of list
  1024.                 UNITLISTITER iter=mlMap[ptClick.x][ptClick.y].ulUnitList.begin();
  1025.                 PUNITINFO pUnitInfo=*iter;
  1026.                 //check that if this unit belongs to the current team
  1027.                 if(pUnitInfo->iTeam==iCurrentTeam)
  1028.                 {
  1029.                     //belongs to current team
  1030.                     //one unit?
  1031.                     if(mlMap[ptClick.x][ptClick.y].ulUnitList.size()==1)
  1032.                     {
  1033.                         //a single unit(already contained in pUnitInfo)
  1034.                         //is this the current unit?
  1035.                         if(pUnitInfo==pCurrentUnit)
  1036.                         {
  1037.                             //this is the current unit
  1038.                             iGameState=GS_IDLE;//return to the neutral gamestate
  1039.                         }
  1040.                         else
  1041.                         {
  1042.                             //this is not the current unit
  1043.                             //does this unit have any movement points left?
  1044.                             if(pUnitInfo->iMovePoints>0)
  1045.                             {
  1046.                                 //has movement points left
  1047.                                 //push the current unit to front of team list
  1048.                                 if(pCurrentUnit) TeamUnitList.push_front(pCurrentUnit);
  1049.                                 pCurrentUnit=NULL;
  1050.                                 //set holding to false for the new unit
  1051.                                 pUnitInfo->bHolding=false;
  1052.                                 //remove new unit from team list
  1053.                                 TeamUnitList.remove(pUnitInfo);
  1054.                                 //put new unit in front of team list
  1055.                                 TeamUnitList.push_front(pUnitInfo);
  1056.                                 //go to gs_nextunit
  1057.                                 iGameState=GS_NEXTUNIT;
  1058.                             }
  1059.                             else
  1060.                             {
  1061.                                 //does not have movement points left
  1062.                                 //go back to gs_idle
  1063.                                 iGameState=GS_IDLE;
  1064.                             }
  1065.                         }
  1066.                     }
  1067.                     else
  1068.                     {
  1069.                         //place the current unit at the front of the list
  1070.                         if(pCurrentUnit) TeamUnitList.push_front(pCurrentUnit);
  1071.                         //a stack of units
  1072.                         iGameState=GS_CLICKSTACK;
  1073.                     }
  1074.                 }
  1075.                 else
  1076.                 {
  1077.                     //does not belong to current team
  1078.                     iGameState=GS_CLICKCENTER;//we want to center on this map location
  1079.                 }
  1080.             }
  1081.         }break;
  1082.     case GS_CLICKCENTER:
  1083.         {
  1084.             //center on clicked tile
  1085.             POINT ptPlot=TilePlotter.PlotTile(ptClick);//plot tile
  1086.             ptPlot.x-=(Scroller.GetScreenSpaceWidth()/2);//adjust by half screenspace
  1087.             ptPlot.y-=(Scroller.GetScreenSpaceHeight()/2);
  1088.             Scroller.SetAnchor(&ptPlot);//set anchor
  1089.             Renderer.AddRect(Scroller.GetScreenSpace());
  1090.             //return to GS_IDLE
  1091.             iGameState=GS_IDLE;
  1092.         }break;
  1093.     case GS_CLICKSTACK:
  1094.         {
  1095.             //prepare the stack
  1096.             int count;
  1097.             for(count=0;count<20;count++)//clear out the list
  1098.                 SelectUnitList[count]=NULL;
  1099.             //reset count to 0
  1100.             count=0;
  1101.             //iterate through the list of units at the current map location
  1102.             UNITLISTITER iter;//iterator
  1103.             PUNITINFO pUnitInfo;//unit info
  1104.             for(iter=mlMap[ptClick.x][ptClick.y].ulUnitList.begin();count<20 && iter!=mlMap[ptClick.x][ptClick.y].ulUnitList.end();iter++)//iterate through list
  1105.             {
  1106.                 pUnitInfo=*iter;//grab the unit
  1107.                 //place unit in list
  1108.                 SelectUnitList[count]=pUnitInfo;
  1109.                 //add 1 to count
  1110.                 count++;
  1111.             }
  1112.             //send to next gamestate
  1113.             iGameState=GS_PICKUNIT;
  1114.         }break;
  1115.     case GS_PICKUNIT:
  1116.         {
  1117.             //no scrolling
  1118.             Renderer.ScrollFrame(0,0);
  1119.             //update frame
  1120.             Renderer.UpdateFrame();
  1121.             //place select window onto display
  1122.             DDBLTFX ddbltfx;
  1123.             DDBLTFX_Clear(&ddbltfx);
  1124.             ddbltfx.dwFillColor=dwSelectWindowColor;
  1125.             lpddsBack->Blt(&rcSelectWindow,NULL,NULL,DDBLT_WAIT | DDBLT_COLORFILL,&ddbltfx);
  1126.             //show the units
  1127.             int cellx,celly;//cell position
  1128.             int cellnum;//number of the cell
  1129.             int pixelx,pixely;//pixel position
  1130.             for(celly=0;celly<4;celly++)
  1131.             {
  1132.                 for(cellx=0;cellx<5;cellx++)
  1133.                 {
  1134.                     cellnum=cellx+celly*5;//calculate the cell number
  1135.                     //check that the unit exists
  1136.                     if(SelectUnitList[cellnum])
  1137.                     {
  1138.                         //calculate pixel position
  1139.                         pixelx=rcSelectWindow.left+ptCellSize.x*cellx;
  1140.                         pixely=rcSelectWindow.top+ptCellSize.y*celly;
  1141.                         //plot the units position
  1142.                         pixelx+=ptUnitOffset.x;
  1143.                         pixely+=ptUnitOffset.y;
  1144.                         //put the unit
  1145.                         tsUnit.PutTile(lpddsBack,pixelx,pixely,SelectUnitList[cellnum]->iType);
  1146.                         //move the pixel to place shielf
  1147.                         pixelx+=ptShieldOffset[SelectUnitList[cellnum]->iType].x;
  1148.                         pixely+=ptShieldOffset[SelectUnitList[cellnum]->iType].y;
  1149.                         //place appropriate shield
  1150.                         if(SelectUnitList[cellnum]->bHolding)
  1151.                         {
  1152.                             //unit is holding
  1153.                             tsShield.PutTile(lpddsBack,pixelx,pixely,iCurrentTeam*2+4);
  1154.                         }
  1155.                         else
  1156.                         {
  1157.                             //unit is not holding
  1158.                             if(SelectUnitList[cellnum]->iMovePoints)
  1159.                             {
  1160.                                 //unit has movement points left
  1161.                                 tsShield.PutTile(lpddsBack,pixelx,pixely,iCurrentTeam*2);
  1162.                             }
  1163.                             else
  1164.                             {
  1165.                                 //unit does not have movememtn points left
  1166.                                 tsShield.PutTile(lpddsBack,pixelx,pixely,iCurrentTeam*2+8);
  1167.                             }
  1168.                         }
  1169.                     }
  1170.                 }
  1171.             }
  1172.             //flip
  1173.             lpddsMain->Flip(0,DDFLIP_WAIT);
  1174.         }break;
  1175.     }
  1176. }
  1177.  
  1178. void RenderFunc(LPDIRECTDRAWSURFACE7 lpddsDst,RECT* rcClip,int xDst,int yDst,int xMap,int yMap)
  1179. {
  1180.     //put background tile
  1181.     tsBack.ClipTile(lpddsDst,rcClip,xDst,yDst,0);
  1182.     //check for an empty list
  1183.     if(!mlMap[xMap][yMap].ulUnitList.empty())
  1184.     {
  1185.         //list is not empty
  1186.         UNITLISTITER iter=mlMap[xMap][yMap].ulUnitList.begin();//get iterator to beginning of list
  1187.         PUNITINFO pUnitInfo=*iter;//grab the item
  1188.         //if this is the current unit
  1189.         if(pUnitInfo==pCurrentUnit)
  1190.         {
  1191.             //this is the current unit
  1192.             if(!bFlash) return;//if flash is "off" dont render
  1193.         }
  1194.         tsUnit.ClipTile(lpddsDst,rcClip,xDst,yDst,pUnitInfo->iType);//place the unit
  1195.         iter++;//move to the next item in the list
  1196.         if(iter==mlMap[xMap][yMap].ulUnitList.end())//if the end of the list, this is a single unit
  1197.         {
  1198.             if(pUnitInfo->bHolding)//if holding position
  1199.             {//holding
  1200.                 tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2+4);//place the shield
  1201.             }
  1202.             else
  1203.             {//not holding
  1204.                 tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2);//place the shield
  1205.             }
  1206.         }
  1207.         else//more than one unit... this is a stack
  1208.         {
  1209.             if(pUnitInfo->bHolding)//if holding position
  1210.             {//holding
  1211.                 tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2+5);//place the shield
  1212.             }
  1213.             else
  1214.             {//not holding
  1215.                 tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2+1);//place the shield
  1216.             }
  1217.         }
  1218.     }
  1219. }
  1220.